--------------------------------------------------------------------------------
-- This package is a thin Ada binding to the Multiple Precision Floating Point
-- Reliable Library. See <http://www.mpfr.org/>.
-- It simply translates in Ada most of the content of the C header file : mpfr.h
--
-- Copyright (C) 2009 Vincent DIEMUNSCH.
-- GNU General Public License.
--
-- This program is free software: you can redistribute it and/or modify it under
-- the terms of the GNU General Public License as published by the Free Software
-- Foundation, either version 3 of the License, or (at your option) any later
-- version.
--
-- This file is distributed in the hope that it will be useful, but WITHOUT ANY
-- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
-- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
--
-- You should have received a copy of the GNU General Public License along with
-- this program.  If not, see <http://www.gnu.org/licenses/>.
--------------------------------------------------------------------------------
--
-- IMPLEMENTATION NOTES :
--    1. THE CURRENT IMPLEMENTATION IS NOT EXHAUSTIVE, refer to mpfr manual to
--       add functions.
--    2. THE SIZE OF TYPES HAVE BEEN TESTED ONLY ON A 32 bits x86 running GNAT/GCC
--    3. NON PORTABLE TYPES : The following types may be different if it's not
--       an Intel 32 bits architecture (for instance a 64 bits architecture or
--       not a GNAT compiler). You need to carefully inspect MPFR.h to know how
--       to declare these types.
--             * mpfr_prec_t
--             * intmax_t
--------------------------------------------------------------------------------
--
-- TO DO : get ternary values through the use of pragma Import_Valued_Procedure
--         note that GNATCOLL uses access value to avoid this problem, a C
--         structure being equivalent to an access to a record).
--         UPDATE TO MPFR 3.0.0 !!

--

with GMP;
with Interfaces.C;         use Interfaces.C;
with Interfaces.C.Strings; use Interfaces.C.Strings;

package MPFR is

   -- Define MPFR version number :
   MPFR_Version_Major      : constant := 2;
   MPFR_Version_Minor      : constant := 4;
   MPFR_Version_PatchLevel : constant := 1;
   MPFR_Version_String     : constant String := "2.4.1";

   package Specific renames GMP.Specific; -- Non portable definitions.

   -- Multiple Precision Floating Point "Reliable" Numbers  :
   type mpfr_t is private;

   -- Definition of rounding modes (DON'T USE GMP_RNDNA!)
   type mpfr_rnd_t is (GMP_RNDNA,  -- round to nearest, with ties away from zero (mpfr_round)
                       GMP_RNDN,   -- round to nearest, with ties to even
                       GMP_RNDZ,   -- round toward zero
                       GMP_RNDU,   -- round toward plus infinity
                       GMP_RNDD,   -- round toward minus infinity
                       GMP_RNDA,   -- round away from zero
		       GMP_RNDF);  -- faithful rounding (not implemented yet)

   for mpfr_rnd_t use (GMP_RNDNA   => -1,
                       GMP_RNDN    =>  0,
                       GMP_RNDZ    =>  1,
                       GMP_RNDU    =>  2,
                       GMP_RNDD    =>  3,
                       GMP_RNDA    =>  4,
                       GMP_RNDF    =>  5);

   -- Define precision :
   subtype mpfr_prec_t is Specific.mpfr_prec_t;


   -- Definition of the standard exponent limits :
   MPFR_EMAX_DEFAULT : constant := 2**30 - 1;
   MPFR_EMIN_DEFAULT : constant := - MPFR_EMAX_DEFAULT;
   subtype mpfr_exp_t is GMP.Specific.mp_exp_t range MPFR_EMIN_DEFAULT .. MPFR_EMAX_DEFAULT;

   -- Stack interface (Is it useful ?)
   type mpfr_kind_t is (MPFR_NAN_KIND,
                        MPFR_INF_KIND,
                        MPFR_ZERO_KIND,
                        MPFR_REGULAR_KIND);

   for mpfr_kind_t use (MPFR_NAN_KIND     => 0,
                        MPFR_INF_KIND     => 1,
                        MPFR_ZERO_KIND    => 2,
                        MPFR_REGULAR_KIND => 3 );

   subtype mpfr_base_arg is int range 2 .. 36;

   -- Largest Integer Size :
   subtype intmax_t is GMP.Specific.intmax_t;


   -----------------------------------------------
   -- Multiple Precision Floating Point Numbers --
   -----------------------------------------------

   -- 5.1 INITIALIZATION :
   procedure mpfr_set_default_prec (prec : mpfr_prec_t);
   function  mpfr_get_default_prec return mpfr_prec_t;
   -- Set the default precision to be at least prec bits. All subsequent calls
   -- to mpf_init will use this precision, but previously initialized variables
   -- are unaffected.
   -- Return the default precision actually used.

   procedure mpfr_init   (x : in out mpfr_t);
   procedure mpfr_init2  (x : in out mpfr_t; prec : mpfr_prec_t);
   -- Initialize x to NaN, and set its precision to be at least prec bits.
   -- Do not call if already initialized !

   procedure mpfr_clear (x : in out mpfr_t);
   -- Free the space occupied by x. Make sure to call this function for all
   -- mpfr_t variables when you are done with them.

   procedure mpfr_set_prec (x : in out mpfr_t; prec : mpfr_prec_t);
   -- Reset the precision of x to be exactly prec bits, and set its value to NaN.
   -- The previous value stored in x is lost. It is equivalent to a call to
   -- mpfr_clear(x) followed by a call to mpfr_init2(x, prec), but more efficient.
   function mpfr_get_prec (x : mpfr_t) return mpfr_prec_t;
   -- Return the precision actually used for assignments of x, i.e. the number
   -- of bits used to store its significand.

   -- 5.2 ASSIGNEMENT :
   procedure mpfr_set     (rop : in out mpfr_t; op : mpfr_t; rnd : mpfr_rnd_t);
   procedure mpfr_set_ui  (rop : in out mpfr_t; op : unsigned_long; rnd : mpfr_rnd_t);
   procedure mpfr_set_si  (rop : in out mpfr_t; op : long; rnd : mpfr_rnd_t);
   procedure mpfr_set_sj  (rop : in out mpfr_t; op : intmax_t; rnd : mpfr_rnd_t);
   procedure mpfr_set_flt (rop : in out mpfr_t; op : float; rnd : mpfr_rnd_t);
   procedure mpfr_set_d   (rop : in out mpfr_t; op : double; rnd : mpfr_rnd_t);
   procedure mpfr_set_ld  (rop : in out mpfr_t; op : long_double; rnd : mpfr_rnd_t);
   procedure mpfr_set_z   (rop : in out mpfr_t; op : GMP.mpz_t; rnd : mpfr_rnd_t);
   procedure mpfr_set_q   (rop : in out mpfr_t; op : GMP.mpq_t; rnd : mpfr_rnd_t);
   procedure mpfr_set_f   (rop : in out mpfr_t; op : GMP.mpf_t; rnd : mpfr_rnd_t);

   procedure mpfr_set_str(rop : in out mpfr_t; s : Chars_Ptr; base : GMP.Base_Arg; rnd : mpfr_rnd_t);
   -- Set rop to the value of the string s in base base, rounded in the direction
   -- rnd. See the documentation of mpfr_strtofr for a detailed description of
   -- the valid string formats. Contrary to mpfr_strtofr, mpfr_set_str requires
   -- the whole string to represent a valid floating-point number.
   -- This function returns 0 if the entire string up to the final null character
   -- is a valid number in base base; otherwise it returns -1, and rop may have changed.

   procedure mpfr_set_inf (x : in out mpfr_t; sign : int);
   procedure mpfr_set_nan (x : in out mpfr_t);
   -- Set the variable x to infinity or NaN (Not-a-Number) respectively.
   -- In mpfr_set_inf, x is set to plus infinity iff sign is nonnegative.
   procedure mpfr_swap (x,y : in out mpfr_t);
   -- Swap the values x and y efficiently. Warning: the precisions are exchanged
   -- too; in case the precisions are different, mpfr_swap is thus not equivalent
   -- to three mpfr_set calls using a third auxiliary variable.

   -- 5.3 COMBINED INITIALIZATION AND ASSIGNEMENT : --

   procedure mpfr_init_set_str (x : in out mpfr_t; str : Chars_Ptr; base : GMP.Base_Arg; rnd : mpfr_rnd_t);
   -- Initialize x and set its value from the string s in base base, rounded in the direction rnd. See
   -- mpfr_set_str.


   -- 5.4 CONVERSION : --
   function  mpfr_get_flt (op  : mpfr_t; rnd : mpfr_rnd_t) return Float;
   function  mpfr_get_d   (op  : mpfr_t; rnd : mpfr_rnd_t) return Double;
   function  mpfr_get_ld  (op  : mpfr_t; rnd : mpfr_rnd_t) return Long_Double;
   procedure mpfr_get_z   (rop : in out GMP.mpz_t; op : mpfr_t; rnd : mpfr_rnd_t);
   -- Convert op to a mpz_t, after rounding it with respect to rnd. If op is NaN
   -- or Inf, the result is undefined.

   function mpfr_get_str (str      : Chars_Ptr;
                          expptr   : GMP.mp_exp_t_ptr;
                          base     : mpfr_base_arg;
                          n_digits : size_t;
                          op       : mpfr_t;
                          rnd      : mpfr_rnd_t) return Chars_Ptr;
   -- Convert op to a string of digits in base b, with rounding in the direction rnd, where n is either
   -- zero (see below) or the number of significant digits; in the latter case, n must be greater or
   -- equal to 2. The base may vary from 2 to 36.
   -- The generated string is a fraction, with an implicit radix point immediately to the left of the
   -- firrst digit.
   -- If str is a null pointer, space for the significand is allocated using the current allocation
   -- function, and a pointer to the string is returned. To free the returned string, you must use
   -- mpfr_free_str.
   -- A pointer to the string is returned, unless there is an error, in which case a null pointer is
   -- returned.

   procedure mpfr_free_str (str : Chars_ptr);
   -- Free a string allocated by mpfr_get_str using the current unallocation function (preliminary
   -- interface). The block is assumed to be strlen(str )+1 bytes. For more information about
   -- how it is done: see Section "Custom Allocation" in GNU MP.

   -- 5.5 BASIC ARITHMETIC :
   -- Note : we forget the "ternary value", returned by the C mpfr functions
   --        since it gives an idea if the value was exact (0), rounded above (>0)
   --        or rounded behind (<0).
   procedure mpfr_add   (rop : in out mpfr_t; op1, op2 : mpfr_t; rnd : mpfr_rnd_t);
   procedure mpfr_add_ui(rop : in out mpfr_t; op1 : mpfr_t; op2 : unsigned_long; rnd : mpfr_rnd_t);
   procedure mpfr_add_si(rop : in out mpfr_t; op1 : mpfr_t; op2 : long; rnd : mpfr_rnd_t);
   procedure mpfr_add_z (rop : in out mpfr_t; op1 : mpfr_t; op2 : GMP.mpz_t; rnd : mpfr_rnd_t);
   procedure mpfr_add_q (rop : in out mpfr_t; op1 : mpfr_t; op2 : GMP.mpq_t; rnd : mpfr_rnd_t);
   -- Set rop to op1 + op2 rounded in the direction rnd. For types having no
   -- signed zero, it is considered unsigned.

   procedure mpfr_sub   (rop : in out mpfr_t; op1, op2 : mpfr_t; rnd : mpfr_rnd_t);
   procedure mpfr_ui_sub(rop : in out mpfr_t; op1 : unsigned_long; op2 : mpfr_t; rnd : mpfr_rnd_t);
   procedure mpfr_sub_ui(rop : in out mpfr_t; op1 : mpfr_t; op2 : unsigned_long; rnd : mpfr_rnd_t);
   procedure mpfr_si_sub(rop : in out mpfr_t; op1 : long; op2 : mpfr_t; rnd : mpfr_rnd_t);
   procedure mpfr_sub_si(rop : in out mpfr_t; op1 : mpfr_t; op2 : long; rnd : mpfr_rnd_t);
   procedure mpfr_sub_z (rop : in out mpfr_t; op1 : mpfr_t; op2 : GMP.mpz_t; rnd : mpfr_rnd_t);
   procedure mpfr_sub_q (rop : in out mpfr_t; op1 : mpfr_t; op2 : GMP.mpq_t; rnd : mpfr_rnd_t);
   -- Set rop to op1 - op2 rounded in the direction rnd. For types having no
   -- signed zero it is considered unsigned.

   procedure mpfr_mul   (rop : in out mpfr_t; op1, op2 : mpfr_t; rnd : mpfr_rnd_t);
   procedure mpfr_mul_ui(rop : in out mpfr_t; op1 : mpfr_t; op2 : unsigned_long; rnd : mpfr_rnd_t);
   procedure mpfr_mul_si(rop : in out mpfr_t; op1 : mpfr_t; op2 : long; rnd : mpfr_rnd_t);
   procedure mpfr_mul_z (rop : in out mpfr_t; op1 : mpfr_t; op2 : GMP.mpz_t; rnd : mpfr_rnd_t);
   procedure mpfr_mul_q (rop : in out mpfr_t; op1 : mpfr_t; op2 : GMP.mpq_t; rnd : mpfr_rnd_t);
   -- Set rop to op1*op2 rounded in the direction rnd. When a result is zero, its
   -- sign is the product of the signs of the operands (for types having no
   -- signed zero, it is considered positive).

   procedure mpfr_sqr (rop : in out mpfr_t; op : mpfr_t; rnd : mpfr_rnd_t);
   -- Set rop to op**2 rounded in the direction rnd.

   procedure mpfr_div   (rop : in out mpfr_t; op1, op2 : mpfr_t; rnd : mpfr_rnd_t);
   procedure mpfr_ui_div(rop : in out mpfr_t; op1 : unsigned_long; op2 : mpfr_t; rnd : mpfr_rnd_t);
   procedure mpfr_div_ui(rop : in out mpfr_t; op1 : mpfr_t; op2 : unsigned_long; rnd : mpfr_rnd_t);
   procedure mpfr_si_div(rop : in out mpfr_t; op1 : long; op2 : mpfr_t; rnd : mpfr_rnd_t);
   procedure mpfr_div_si(rop : in out mpfr_t; op1 : mpfr_t; op2 : long; rnd : mpfr_rnd_t);
   procedure mpfr_div_z (rop : in out mpfr_t; op1 : mpfr_t; op2 : GMP.mpz_t; rnd : mpfr_rnd_t);
   procedure mpfr_div_q (rop : in out mpfr_t; op1 : mpfr_t; op2 : GMP.mpq_t; rnd : mpfr_rnd_t);
   -- Set rop to op1/op2 rounded in the direction rnd. When a result is zero,
   -- its sign is the product of the signs of the operands (for types having no
   -- signed zero, it is considered positive).

   procedure mpfr_sqrt    (rop : in out mpfr_t; op : mpfr_t;        rnd : mpfr_rnd_t);
   procedure mpfr_sqrt_ui (rop : in out mpfr_t; op : unsigned_long; rnd : mpfr_rnd_t);
   -- Set rop to sqrt(op) rounded in the direction rnd. Return -0 if op is -0
   -- (to be consistent with the IEEE 754-1985 standard). Set rop to NaN if op
   -- is negative.

   procedure mpfr_cbrt (rop : in out mpfr_t; op : mpfr_t; rnd : mpfr_rnd_t);
   procedure mpfr_root (rop : in out mpfr_t; op : mpfr_t; k : unsigned_long; rnd : mpfr_rnd_t);
   -- Set rop to the cubic root (resp. the kth root) of op rounded in the
   -- direction rnd. An odd (resp. even) root of a negative number (including
   -- -Inf) returns a negative number (resp. NaN). The kth root of -0 is defined
   -- to be -0, whatever the parity of k.

   procedure mpfr_pow    (rop : in out mpfr_t; op1, op2 : mpfr_t; rnd : mpfr_rnd_t);
   procedure mpfr_pow_ui (rop : in out mpfr_t; op1 : mpfr_t; op2 : unsigned_long; rnd : mpfr_rnd_t);
   procedure mpfr_pow_si (rop : in out mpfr_t; op1 : mpfr_t; op2 : long; rnd : mpfr_rnd_t);
   procedure mpfr_pow_z  (rop : in out mpfr_t; op1 : mpfr_t; op2 : GMP.mpz_t; rnd : mpfr_rnd_t);
   procedure mpfr_ui_pow_ui (rop : in out mpfr_t; op1, op2 : mpfr_t; rnd : mpfr_rnd_t);
   procedure mpfr_ui_pow (rop : in out mpfr_t; op1 : unsigned_long; op2 : mpfr_t; rnd : mpfr_rnd_t);
   -- Set rop to op1op2, rounded in the direction rnd. Special values are
   -- currently handled as described in the ISO C99 standard for the pow function
   -- (note this may change in future versions)...


   procedure mpfr_neg (rop : in out mpfr_t; op : mpfr_t; rnd : mpfr_rnd_t);
   -- Set rop to -op rounded in the direction rnd. Just changes the sign if rop
   -- and op are the same variable.
   procedure mpfr_abs (rop : in out mpfr_t; op : mpfr_t; rnd : mpfr_rnd_t);
   -- Set rop to the absolute value of op, rounded in the direction rnd. Just
   -- changes the sign if rop and op are the same variable.


   -- 5.6 COMPARISON FUNCTIONS :
   function mpfr_cmp    (op1, op2 : mpfr_t)             return int;
   function mpfr_cmp_si (op1      : mpfr_t; op2 : long) return int;
   -- Compare op1 and op2. Return a positive value if op1 > op2,
   -- zero if op1 = op2 , and a negative value if op1 < op2.

   function mpfr_cmpabs         (op1, op2 : mpfr_t) return int;
   -- Compare |op1| and |op2|. Return a positive value if |op1| > |op2|,
   -- zero if |op1| = |op2|, and a negative value if |op1| < |op2|. If one of
   -- the operands is NaN, set the erange flag and return zero.

   function mpfr_nan_p    (op : mpfr_t) return int;
   function mpfr_inf_p    (op : mpfr_t) return int;
   function mpfr_number_p (op : mpfr_t) return int;
   function mpfr_zero_p   (op : mpfr_t) return int;
   -- Return non-zero if op is respectively NaN, an infinity, an ordinary number
   -- (i.e. neither NaN nor an infinity) or zero. Return zero otherwise.

   function mpfr_sgn (op : mpfr_t) return int;
   -- Return a positive value if op > 0, zero if op = 0, and a negative value
   -- if op < 0. If the operand is NaN, set the erange flag and return zero.

   function mpfr_greater_p      (op1, op2 : mpfr_t) return int; -- Non-zero if op1 > op2.
   function mpfr_greaterequal_p (op1, op2 : mpfr_t) return int; -- Non-zero if op1 >= op2.
   function mpfr_less_p         (op1, op2 : mpfr_t) return int; -- Non-zero if op1 < op2.
   function mpfr_lessequal_p    (op1, op2 : mpfr_t) return int; -- Non-zero if op1 <= op2.
   function mpfr_lessgreater_p  (op1, op2 : mpfr_t) return int; -- Non-zero if op1 < op2 or op1 > op2.
   function mpfr_equal_p        (op1, op2 : mpfr_t) return int; -- Non-zero if op1 = op2.
   function mpfr_unordered_p    (op1, op2 : mpfr_t) return int; -- Non-zero if op1 or op2 is NaN.

   -- 5.7 SPECIAL FUNCTIONS :

   procedure mpfr_log   (rop : in out mpfr_t; op : mpfr_t; rnd : mpfr_rnd_t);
   procedure mpfr_log2  (rop : in out mpfr_t; op : mpfr_t; rnd : mpfr_rnd_t);
   procedure mpfr_log10 (rop : in out mpfr_t; op : mpfr_t; rnd : mpfr_rnd_t);
   -- Set rop to the natural logarithm of op, log2 op or log10 op, respectively,
   -- rounded in the direction rnd. Return -Inf if op is -0 (i.e. the sign of
   -- the zero has no influence on the result).

   procedure mpfr_exp   (rop : in out mpfr_t; op : mpfr_t; rnd : mpfr_rnd_t);
   procedure mpfr_exp2  (rop : in out mpfr_t; op : mpfr_t; rnd : mpfr_rnd_t);
   procedure mpfr_exp10 (rop : in out mpfr_t; op : mpfr_t; rnd : mpfr_rnd_t);
   -- Set rop to the exponential of op, to 2op or to 10op, respectively, rounded
   -- in the direction rnd.

   procedure mpfr_cos (rop : in out mpfr_t; op : mpfr_t; rnd : mpfr_rnd_t);
   procedure mpfr_sin (rop : in out mpfr_t; op : mpfr_t; rnd : mpfr_rnd_t);
   procedure mpfr_tan (rop : in out mpfr_t; op : mpfr_t; rnd : mpfr_rnd_t);
   -- Set rop to the cosine of op, sine of op, tangent of op, rounded in the
   -- direction rnd.

   procedure mpfr_sec (rop : in out mpfr_t; op : mpfr_t; rnd : mpfr_rnd_t);
   procedure mpfr_csc (rop : in out mpfr_t; op : mpfr_t; rnd : mpfr_rnd_t);
   procedure mpfr_cot (rop : in out mpfr_t; op : mpfr_t; rnd : mpfr_rnd_t);
   -- Set rop to the secant of op, cosecant of op, cotangent of op, rounded in
   -- the direction rnd.

   procedure mpfr_sin_cos (sop, cop : in out mpfr_t; op : mpfr_t; rnd : mpfr_rnd_t);
   -- Set simultaneously sop to the sine of op and cop to the cosine of op,
   -- rounded in the direction rnd with the corresponding precisions of sop and
   -- cop, which must be different variables.

   procedure mpfr_acos (rop : in out mpfr_t; op : mpfr_t; rnd : mpfr_rnd_t);
   procedure mpfr_asin (rop : in out mpfr_t; op : mpfr_t; rnd : mpfr_rnd_t);
   procedure mpfr_atan (rop : in out mpfr_t; op : mpfr_t; rnd : mpfr_rnd_t);
   -- Set rop to the arc-cosine, arc-sine or arc-tangent of op, rounded in the
   -- direction rnd. Note that since acos(-1) returns the floating-point number
   -- closest to PI according to the given rounding mode, this number might not
   -- be in the output range 0 <= rop < PI of the arc-cosine function; still, the
   -- result lies in the image of the output range by the rounding function. The
   -- same holds for asin(-1), asin(1), atan(-Inf), atan(+Inf).

   procedure mpfr_atan2 (rop : in out mpfr_t; op : mpfr_t; rnd : mpfr_rnd_t);
   -- Set rop to the arc-tangent2 of y and x, rounded in the direction rnd.
   -- See MPFR Manual.

   procedure mpfr_cosh (rop : in out mpfr_t; op : mpfr_t; rnd : mpfr_rnd_t);
   procedure mpfr_sinh (rop : in out mpfr_t; op : mpfr_t; rnd : mpfr_rnd_t);
   procedure mpfr_tanh (rop : in out mpfr_t; op : mpfr_t; rnd : mpfr_rnd_t);
   -- Set rop to the hyperbolic cosine, sine or tangent of op, rounded in the
   -- direction rnd.
   procedure mpfr_sinh_cosh (sop, cop : in out mpfr_t; op : mpfr_t; rnd : mpfr_rnd_t);
   -- Set simultaneously sop to the hyperbolic sine of op and cop to the
   -- hyperbolic cosine of op, rounded in the direction rnd with the corresponding
   -- precision of sop and cop which must be different variables. Return 0 iff
   -- both results are exact.
   procedure mpfr_sech (rop : in out mpfr_t; op : mpfr_t; rnd : mpfr_rnd_t);
   procedure mpfr_csch (rop : in out mpfr_t; op : mpfr_t; rnd : mpfr_rnd_t);
   procedure mpfr_coth (rop : in out mpfr_t; op : mpfr_t; rnd : mpfr_rnd_t);
   -- Set rop to the hyperbolic secant of op, cosecant of op, cotangent of op,
   -- rounded in the direction rnd.
   procedure mpfr_acosh (rop : in out mpfr_t; op : mpfr_t; rnd : mpfr_rnd_t);
   procedure mpfr_asinh (rop : in out mpfr_t; op : mpfr_t; rnd : mpfr_rnd_t);
   procedure mpfr_atanh (rop : in out mpfr_t; op : mpfr_t; rnd : mpfr_rnd_t);
   -- Set rop to the inverse hyperbolic cosine, sine or tangent of op, rounded
   -- in the direction rnd.

   procedure mpfr_fac_ui (rop : in out mpfr_t; op : unsigned_long; rnd : mpfr_rnd_t);
   -- Set rop to the factorial of the unsigned long int op, rounded in the
   -- direction rnd.
   procedure mpfr_log1p (rop : in out mpfr_t; op : mpfr_t; rnd : mpfr_rnd_t);
   -- Set rop to the logarithm of one plus op, rounded in the direction rnd.
   procedure mpfr_expm1 (rop : in out mpfr_t; op : mpfr_t; rnd : mpfr_rnd_t);
   -- Set rop to the exponential of op minus one, rounded in the direction rnd.
   procedure mpfr_eint (y : in out mpfr_t; x : mpfr_t; rnd : mpfr_rnd_t);
   -- Set y to the exponential integral of x, rounded in the direction rnd. For
   -- positive x, the exponential integral is the sum of Euler's constant, of
   -- the logarithm of x, and of the sum for k from 1 to infinity of xk/k/k!.
   -- For negative x, the returned value is NaN.
   procedure mpfr_li2 (rop : in out mpfr_t; op : mpfr_t; rnd : mpfr_rnd_t);
   -- Set rop to real part of the dilogarithm of op, rounded in the direction
   -- rnd mode. See Manual for details.
   procedure mpfr_gamma (rop : in out mpfr_t; op : mpfr_t; rnd : mpfr_rnd_t);
   -- Set rop to the value of the Gamma function on op, rounded in the direction
   -- rnd. When op is a negative integer, NaN is returned.
   procedure mpfr_lngamma (rop : in out mpfr_t; op : mpfr_t; rnd : mpfr_rnd_t);
   -- Set rop to the value of the logarithm of the Gamma function on op, rounded
   -- rnd. When -2k-1 =< x =< -2k, k being a non-negative integer, NaN is returned.
   -- See also mpfr_lgamma.
   procedure mpfr_lgamma (rop : in out mpfr_t; signp : access int; op : mpfr_t; rnd : mpfr_rnd_t);
   -- Set rop to the value of the logarithm of the absolute value of the Gamma
   -- function on op, rounded in the direction rnd. The sign (+1 or -1) of
   -- Gamma(op) is returned in the object pointed to by signp. When op is an
   -- infinity or a non-positive integer, +Inf is returned. When op is NaN,
   -- -Inf or a negative integer, *signp is undefined, and when op is +/- 0,
   -- *signp is the sign of the zero.
   procedure mpfr_zeta    (rop : in out mpfr_t; op : mpfr_t; rnd : mpfr_rnd_t);
   procedure mpfr_zeta_ui (rop : in out mpfr_t; op : unsigned_long; rnd : mpfr_rnd_t);
   -- Set rop to the value of the Riemann Zeta function on op, rounded in the
   -- direction rnd.
   procedure mpfr_erf (rop : in out mpfr_t; op : mpfr_t; rnd : mpfr_rnd_t);
   -- Set rop to the value of the error function on op, rounded in the direction rnd.
   procedure mpfr_erfc (rop : in out mpfr_t; op : mpfr_t; rnd : mpfr_rnd_t);
   -- Set rop to the value of the complementary error function on op, rounded in
   -- the direction rnd.
   procedure mpfr_j0 (rop : in out mpfr_t; op : mpfr_t; rnd : mpfr_rnd_t);
   procedure mpfr_j1 (rop : in out mpfr_t; op : mpfr_t; rnd : mpfr_rnd_t);
   procedure mpfr_jn (rop : in out mpfr_t; n : long; op : mpfr_t; rnd : mpfr_rnd_t);
   -- Set rop to the value of the first kind Bessel function of order 0, 1 and n
   -- on op, rounded in the direction rnd. When op is NaN, rop is always set to
   -- NaN. When op is plus or minus Infinity, rop is set to +0. When op is zero,
   -- and n is not zero, rop is +0 or -0 depending on the parity and sign of n,
   -- and the sign of op.
   procedure mpfr_y0 (rop : in out mpfr_t; op : mpfr_t; rnd : mpfr_rnd_t);
   procedure mpfr_y1 (rop : in out mpfr_t; op : mpfr_t; rnd : mpfr_rnd_t);
   procedure mpfr_yn (rop : in out mpfr_t; n : long; op : mpfr_t; rnd : mpfr_rnd_t);
   -- Set rop to the value of the second kind Bessel function of order 0, 1 and n
   -- on op, rounded in the direction rnd. When op is NaN or negative, rop is
   -- always set to NaN. When op is +Inf, rop is +0. When op is zero, rop is +Inf
   -- or -Inf depending on the parity and sign of n.
   procedure mpfr_fma (rop : in out mpfr_t; op1, op2, op3 : mpfr_t; rnd : mpfr_rnd_t);
   -- Set rop to (op1 * op2) + op3, rounded in the direction rnd.
   procedure mpfr_fms (rop : in out mpfr_t; op1, op2, op3 : mpfr_t; rnd : mpfr_rnd_t);
   -- Set rop to (op1 * op2) - op3, rounded in the direction rnd.
   procedure mpfr_agm (rop : in out mpfr_t; op1, op2 : mpfr_t; rnd : mpfr_rnd_t);
   -- Set rop to the arithmetic-geometric mean of op1 and op2, rounded in the
   -- direction rnd. The arithmetic-geometric mean is the common limit of the
   -- sequences u[n] and v[n], where u[0]=op1, v[0]=op2, u[n+1] is the arithmetic
   -- mean of u[n] and v[n], and v[n+1] is the geometric mean of u[n] and v[n].
   -- If any operand is negative, the return value is NaN.
   procedure mpfr_hypot (rop : in out mpfr_t; x, y : mpfr_t; rnd : mpfr_rnd_t);
   -- Set rop to the Euclidean norm of x and y, i.e. sqrt(x**2 + y**2), rounded
   -- in the direction rnd. Special values are currently handled as described
   -- in Section F.9.4.3 of the ISO C99 standard, for the hypot function (note
   -- this may change in future versions): If x or y is an infinity, then plus
   -- infinity is returned in rop, even if the other number is NaN.


   procedure mpfr_const_log2    (rop : in out mpfr_t; rnd : mpfr_rnd_t);
   procedure mpfr_const_pi      (rop : in out mpfr_t; rnd : mpfr_rnd_t);
   procedure mpfr_const_euler   (rop : in out mpfr_t; rnd : mpfr_rnd_t);
   procedure mpfr_const_catalan (rop : in out mpfr_t; rnd : mpfr_rnd_t);
   -- Set rop to the logarithm of 2, the value of Pi, of Euler's constant 0.577...,
   -- of Catalan's constant 0.915..., respectively, rounded in the direction rnd.
   -- These functions cache the computed values to avoid other calculations if a
   -- lower or equal precision is requested. To free these caches, use mpfr_free_cache.
   procedure mpfr_free_cache;
   -- Free various caches used by MPFR internally, in particular the caches
   -- used by the functions computing constants. You should call this function
   -- before terminating a thread, even if you did not call these functions
   -- directly (they could have been called internally).

   -- 5.8 INPUT AND OUTPUT :
   -- This section describes functions that perform input from an input/output
   -- stream, and functions that output to an input/output stream. Passing a null
   -- pointer for a stream to any of these functions will make them read from
   -- stdin and write to stdout, respectively.
   -- When using any of these functions, you must include the <stdio.h> standard
   -- header before mpfr.h, to allow mpfr.h to define prototypes for these functions.

   function mpfr_out_str(stream : access int := null; base : int; n : size_t;
                         op     : mpfr_t; rnd : mpfr_rnd_t) return size_t;
   procedure mpfr_out_str(stream : access int := null; base : int; n : size_t;
                         op     : mpfr_t; rnd : mpfr_rnd_t);
   -- Output op on stream stream, as a string of digits in base base, rounded in
   -- the direction rnd. The base may vary from 2 to 36. Print n significant
   -- digits exactly, or if n is 0, enough digits so that op can be read back
   --- exactly (see mpfr_get_str).
   -- In addition to the significant digits, a decimal point (defined by the
   -- current locale) at the right of the first digit and a trailing exponent in
   -- base 10, in the form 'eNNN', are printed. If base is greater than 10, '@'
   -- will be used instead of 'e' as exponent delimiter.
   -- Return the number of bytes written, or if an error occurred, return 0.
   -- NOTE : stream MUST BE NULL.
--
--  size_t mpfr_inp_str (mpfr t rop, FILE *stream, int base, mp rnd t

--  rnd)
--  Input a string in base base from stream stream, rounded in the direction rnd, and put the
--  read float in rop.
--  This function reads a word (defined as a sequence of characters between whitespace) and
--  parses it using mpfr_set_str (it may change). See the documentation of mpfr_strtofr for
--  a detailed description of the valid string formats.
--  Return the number of bytes read, or if an error occurred, return 0.

   -- 5.10 MISCELLANEOUS :
   function mpfr_get_exp (x : mpfr_t) return mpfr_exp_t;
   -- Get the exponent of x, assuming that x is a non-zero ordinary number and
   -- the significand is chosen in [1/2,1).
   procedure mpfr_set_exp (x : in out mpfr_t; mp : mpfr_exp_t);
   -- Set the exponent of x if e is in the current exponent range, and return 0
   -- (even if x is not a non-zero ordinary number); otherwise, return a non-zero value.
   -- The significand is assumed to be in [1/2,1).

   -- 5.11 ROUNDING MODE RELATED FUNCTIONS :
   procedure mpfr_prec_round (x : in out mpfr_t; prec : mpfr_prec_t; rnd : mpfr_rnd_t);
   -- Round x according to rnd with precision prec. If prec is greater or equal
   -- to the precision of x, then new space is allocated for the significand,
   -- and it is filled with zeros. Otherwise, the significand is rounded to
   -- precision prec with the given direction. In both cases, the precision of x
   -- is changed to prec.

   -- 5.12 EXCEPTION RELATED FUNCTIONS :
   procedure mpfr_clear_flags;
   -- Clear all global flags (underflow, overflow, inexact, invalid, erange).
   function mpfr_underflow_p  return int;
   function mpfr_overflow_p   return int;
   function mpfr_nanflag_p    return int;
   function mpfr_inexflag_p   return int;
   function mpfr_erangeflag_p return int;
   -- Return the corresponding (underflow, overflow, invalid, inexact, erange)
   -- flag, which is nonzero iff the flag is set.

private

   -- Definition of sign :
   type mpfr_sign_t is new int;

   ------------
   -- mpfr_t --
   ------------

   -- Definition of the main structure :
   type mpfr_struct is record
      mpfr_prec : mpfr_prec_t;
      mpfr_sign : mpfr_sign_t;
      mpfr_exp  : mpfr_exp_t;
      mpfr_d    : GMP.mp_limb_a;
   end record;

   type mpfr_t   is array (1 .. 1) of mpfr_struct;
   type mpfr_ptr is access all mpfr_struct;


   ----------------
   -- Convention --
   ----------------

   Pragma Convention (C, mpfr_rnd_t);
   Pragma Convention (C, mpfr_kind_t);
   Pragma Convention (C, mpfr_sign_t);
   Pragma Convention (C, mpfr_struct);
   Pragma Convention (C, mpfr_t);
   Pragma Convention (C, mpfr_ptr);


   ------------
   -- Import --
   ------------

   pragma Import (C, mpfr_set_default_prec, "mpfr_set_default_prec");
   pragma Import (C, mpfr_get_default_prec, "mpfr_get_default_prec");
   pragma Import (C, mpfr_init, "mpfr_init");
   pragma Import (C, mpfr_init2, "mpfr_init2");
   pragma Import (C, mpfr_clear, "mpfr_clear");
   pragma Import (C, mpfr_set_prec, "mpfr_set_prec");
   pragma Import (C, mpfr_get_prec, "mpfr_get_prec");

   pragma Import (C, mpfr_set, "mpfr_set");
   pragma Import (C, mpfr_set_ui, "mpfr_set_ui");
   pragma Import (C, mpfr_set_si, "mpfr_set_si");
   pragma Import (C, mpfr_set_sj, "mpfr_set_sj");
   pragma Import (C, mpfr_set_flt, "mpfr_set_flt");
   pragma Import (C, mpfr_set_d, "mpfr_set_d");
   pragma Import (C, mpfr_set_ld, "mpfr_set_ld");
   pragma Import (C, mpfr_set_z, "mpfr_set_z");
   pragma Import (C, mpfr_set_q, "mpfr_set_q");
   pragma Import (C, mpfr_set_f, "mpfr_set_f");
   pragma Import (C, mpfr_set_str, "mpfr_set_str");
   pragma Import (C, mpfr_set_inf, "mpfr_set_inf");
   pragma Import (C, mpfr_set_nan, "mpfr_set_nan");
   pragma Import (C, mpfr_swap, "mpfr_swap");

   pragma Import (C, mpfr_init_set_str, "mpfr_init_set_str");

   pragma Import (C, mpfr_get_flt, "mpfr_get_flt");
   pragma Import (C, mpfr_get_d, "mpfr_get_d");
   pragma Import (C, mpfr_get_ld, "mpfr_get_ld");
   pragma Import (C, mpfr_get_z, "mpfr_get_z");
   pragma Import (C, mpfr_get_str, "mpfr_get_str");
   pragma Import (C, mpfr_free_str, "mpfr_free_str");

   pragma Import (C, mpfr_add, "mpfr_add");
   pragma Import (C, mpfr_add_ui, "mpfr_add_ui");
   pragma Import (C, mpfr_add_si, "mpfr_add_si");
   pragma Import (C, mpfr_add_z, "mpfr_add_z");
   pragma Import (C, mpfr_add_q, "mpfr_add_q");

   pragma Import (C, mpfr_sub, "mpfr_sub");
   pragma Import (C, mpfr_ui_sub, "mpfr_ui_sub");
   pragma Import (C, mpfr_sub_ui, "mpfr_sub_ui");
   pragma Import (C, mpfr_si_sub, "mpfr_si_sub");
   pragma Import (C, mpfr_sub_si, "mpfr_sub_si");
   pragma Import (C, mpfr_sub_z, "mpfr_sub_z");
   pragma Import (C, mpfr_sub_q, "mpfr_sub_q");

   pragma Import (C, mpfr_mul, "mpfr_mul");
   pragma Import (C, mpfr_mul_ui, "mpfr_mul_ui");
   pragma Import (C, mpfr_mul_si, "mpfr_mul_si");
   pragma Import (C, mpfr_mul_z, "mpfr_mul_z");
   pragma Import (C, mpfr_mul_q, "mpfr_mul_q");

   pragma Import (C, mpfr_sqr, "mpfr_sqr");

   pragma Import (C, mpfr_div, "mpfr_div");
   pragma Import (C, mpfr_ui_div, "mpfr_ui_div");
   pragma Import (C, mpfr_div_ui, "mpfr_div_ui");
   pragma Import (C, mpfr_si_div, "mpfr_si_div");
   pragma Import (C, mpfr_div_si, "mpfr_div_si");
   pragma Import (C, mpfr_div_z, "mpfr_div_z");
   pragma Import (C, mpfr_div_q, "mpfr_div_q");

   pragma Import (C, mpfr_sqrt, "mpfr_sqrt");
   pragma Import (C, mpfr_sqrt_ui, "mpfr_sqrt_ui");

   pragma Import (C, mpfr_cbrt, "mpfr_cbrt");
   pragma Import (C, mpfr_root, "mpfr_root");
   pragma Import (C, mpfr_pow, "mpfr_pow");
   pragma Import (C, mpfr_pow_ui, "mpfr_pow_ui");
   pragma Import (C, mpfr_pow_si, "mpfr_pow_si");
   pragma Import (C, mpfr_pow_z, "mpfr_pow_z");
   pragma Import (C, mpfr_ui_pow_ui, "mpfr_ui_pow_ui");
   pragma Import (C, mpfr_ui_pow, "mpfr_ui_pow");

   pragma Import (C, mpfr_neg, "mpfr_neg");
   pragma Import (C, mpfr_abs, "mpfr_abs");

   pragma Import (C, mpfr_cmp, "mpfr_cmp");
   pragma Import (C, mpfr_cmp_si, "mpfr_cmp_si");
   pragma Import (C, mpfr_cmpabs, "mpfr_cmpabs");

   pragma Import (C, mpfr_nan_p, "mpfr_nan_p");
   pragma Import (C, mpfr_inf_p, "mpfr_inf_p");
   pragma Import (C, mpfr_number_p, "mpfr_number_p");
   pragma Import (C, mpfr_zero_p, "mpfr_zero_p");
   pragma Import (C, mpfr_sgn, "mpfr_sgn");

   pragma Import (C, mpfr_greater_p, "mpfr_greater_p");
   pragma Import (C, mpfr_greaterequal_p, "mpfr_greaterequal_p");
   pragma Import (C, mpfr_less_p, "mpfr_less_p");
   pragma Import (C, mpfr_lessequal_p, "mpfr_lessequal_p");
   pragma Import (C, mpfr_lessgreater_p, "mpfr_lessgreater_p");
   pragma Import (C, mpfr_equal_p, "mpfr_equal_p");
   pragma Import (C, mpfr_unordered_p, "mpfr_unordered_p");

   pragma Import (C, mpfr_log, "mpfr_log");
   pragma Import (C, mpfr_log2, "mpfr_log2");
   pragma Import (C, mpfr_log10, "mpfr_log10");
   pragma Import (C, mpfr_exp, "mpfr_exp");
   pragma Import (C, mpfr_exp2, "mpfr_exp2");
   pragma Import (C, mpfr_exp10, "mpfr_exp10");
   pragma Import (C, mpfr_cos, "mpfr_cos");
   pragma Import (C, mpfr_sin, "mpfr_sin");
   pragma Import (C, mpfr_tan, "mpfr_tan");
   pragma Import (C, mpfr_sec, "mpfr_sec");
   pragma Import (C, mpfr_csc, "mpfr_csc");
   pragma Import (C, mpfr_cot, "mpfr_cot");
   pragma Import (C, mpfr_sin_cos, "mpfr_sin_cos");
   pragma Import (C, mpfr_acos, "mpfr_acos");
   pragma Import (C, mpfr_asin, "mpfr_asin");
   pragma Import (C, mpfr_atan, "mpfr_atan");
   pragma Import (C, mpfr_atan2, "mpfr_atan2");
   pragma Import (C, mpfr_cosh, "mpfr_cosh");
   pragma Import (C, mpfr_sinh, "mpfr_sinh");
   pragma Import (C, mpfr_tanh, "mpfr_tanh");
   pragma Import (C, mpfr_sinh_cosh, "mpfr_sinh_cosh");
   pragma Import (C, mpfr_sech, "mpfr_sech");
   pragma Import (C, mpfr_csch, "mpfr_csch");
   pragma Import (C, mpfr_coth, "mpfr_coth");
   pragma Import (C, mpfr_acosh, "mpfr_acosh");
   pragma Import (C, mpfr_asinh, "mpfr_asinh");
   pragma Import (C, mpfr_atanh, "mpfr_atanh");
   pragma Import (C, mpfr_fac_ui, "mpfr_fac_ui");
   pragma Import (C, mpfr_log1p, "mpfr_log1p");
   pragma Import (C, mpfr_expm1, "mpfr_expm1");

   pragma Import (C, mpfr_eint, "mpfr_eint");
   pragma Import (C, mpfr_li2, "mpfr_li2");
   pragma Import (C, mpfr_gamma, "mpfr_gamma");
   pragma Import (C, mpfr_lngamma, "mpfr_lngamma");
   pragma Import (C, mpfr_lgamma, "mpfr_lgamma");
   pragma Import (C, mpfr_zeta, "mpfr_zeta");
   pragma Import (C, mpfr_zeta_ui, "mpfr_zeta_ui");
   pragma Import (C, mpfr_erf, "mpfr_erf");
   pragma Import (C, mpfr_erfc, "mpfr_erfc");
   pragma Import (C, mpfr_j0, "mpfr_j0");
   pragma Import (C, mpfr_j1, "mpfr_j1");
   pragma Import (C, mpfr_jn, "mpfr_jn");
   pragma Import (C, mpfr_y0, "mpfr_y0");
   pragma Import (C, mpfr_y1, "mpfr_y1");
   pragma Import (C, mpfr_yn, "mpfr_yn");
   pragma Import (C, mpfr_fma, "mpfr_fma");
   pragma Import (C, mpfr_fms, "mpfr_fms");
   pragma Import (C, mpfr_agm, "mpfr_agm");
   pragma Import (C, mpfr_hypot, "mpfr_hypot");

   pragma Import (C, mpfr_const_log2, "mpfr_const_log2");
   pragma Import (C, mpfr_const_pi, "mpfr_const_pi");
   pragma Import (C, mpfr_const_euler, "mpfr_const_euler");
   pragma Import (C, mpfr_const_catalan, "mpfr_const_catalan");
   pragma Import (C, mpfr_free_cache, "mpfr_free_cache");

   pragma Import (C, mpfr_out_str, "__gmpfr_out_str");

   pragma Import (C, mpfr_get_exp, "mpfr_get_exp");
   pragma Import (C, mpfr_set_exp, "mpfr_set_exp");

   pragma Import (C, mpfr_prec_round, "mpfr_prec_round");

   pragma Import (C, mpfr_clear_flags, "mpfr_clear_flags");
   pragma Import (C, mpfr_underflow_p, "mpfr_underflow_p");
   pragma Import (C, mpfr_overflow_p, "mpfr_overflow_p");
   pragma Import (C, mpfr_nanflag_p, "mpfr_nanflag_p");
   pragma Import (C, mpfr_inexflag_p, "mpfr_inexflag_p");
   pragma Import (C, mpfr_erangeflag_p, "mpfr_erangeflag_p");

end MPFR;
